package handlers

import (
	"context"
	"errors"
	"fmt"
	"gitee.com/aqchain/backend/models"
	"gitee.com/aqchain/go-ethereum/common"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"math/big"
	"strconv"
)

func (h *Handler) AddTrade(c *gin.Context) {
	err := h.addTrade(c)
	if err != nil {
		c.JSON(200, gin.H{
			"success": false,
			"message": fmt.Sprintf("error %s", err.Error()),
		})
		return
	}

	c.JSON(200, gin.H{
		"success": true,
	})
}

func (h *Handler) addTrade(c *gin.Context) error {
	// 获取并检查参数
	itemID, err := strconv.Atoi(c.PostForm("itemID"))

	fromUserID, err := strconv.Atoi(c.PostForm("fromUserID"))
	toUserID, err := strconv.Atoi(c.PostForm("toUserID"))

	price, err := strconv.Atoi(c.PostForm("price"))
	tradeType, err := strconv.Atoi(c.PostForm("type"))

	if err != nil {
		return errors.New("params error")
	}

	fromUser := models.User{
		ID: uint(fromUserID),
	}
	err = h.db.First(&fromUser).Error
	if err != nil {
		return err
	}

	toUser := models.User{
		ID: uint(toUserID),
	}
	err = h.db.First(&toUser).Error
	if err != nil {
		return err
	}

	item := models.Item{
		ID: uint(itemID),
	}
	err = h.db.Preload("Owner").First(&item).Error
	if err != nil {
		return err
	}

	// 保存数据
	err = h.db.Transaction(func(tx *gorm.DB) error {
		trade := models.Trade{
			ItemID:     uint(itemID),
			Price:      uint(price),
			Type:       uint(tradeType),
			FromUserID: fromUser.ID,
			ToUserID:   toUser.ID,
		}

		ctx := context.Background()
		switch tradeType {
		case 1:
			// 直接转让

			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			transferTx, err := h.client.Transfer(ctx, item.FileHash, common.HexToAddress(fromUser.Address), common.HexToAddress(toUser.Address), big.NewInt(int64(price)))
			if err != nil {
				return err
			}

			trade.TxHash = transferTx

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			if err := tx.Model(&item).Select("OwnerID", "Status", "Price").Updates(models.Item{OwnerID: toUser.ID, Status: 1, Price: 0}).Error; err != nil {
				return err
			}
			if err := tx.Model(models.Trade{}).Where("item_id = ?", item.ID).Updates(models.Trade{Status: 1}).Error; err != nil {
				return err
			}
			break
		case 2:
			// 创建定价
			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			if err := tx.Model(&item).Updates(models.Item{Status: 2, Price: uint(price)}).Error; err != nil {
				return err
			}
			break
		case 3:
			// 定价交易
			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			txHash, err := h.client.Transfer(context.Background(), item.FileHash, common.HexToAddress(fromUser.Address), common.HexToAddress(toUser.Address), big.NewInt(int64(item.Price)))
			if err != nil {
				return err
			}

			trade.TxHash = txHash
			trade.Price = item.Price

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			if err := tx.Model(&item).Select("OwnerID", "Status", "Price").Updates(models.Item{OwnerID: toUser.ID, Status: 1, Price: item.Price}).Error; err != nil {
				return err
			}
			if err := tx.Model(models.Trade{}).Where("item_id = ?", item.ID).Updates(models.Trade{Status: 1}).Error; err != nil {
				return err
			}
			break
		case 4:
			// 创建授权定价
			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			if err := tx.Model(&item).Updates(models.Item{Status: 4, Price: uint(price)}).Error; err != nil {
				return err
			}
			break
		case 5:
			// 购买授权
			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			txHash, err := h.client.SetLicense(context.Background(), item.FileHash, common.HexToAddress(fromUser.Address), common.HexToAddress(toUser.Address), big.NewInt(int64(item.Price)))
			if err != nil {
				return err
			}

			trade.TxHash = txHash
			trade.Price = item.Price

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			break

		case 6:
			// 创建拍卖
			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}

			if err := tx.Model(&item).Updates(models.Item{Status: 3, Price: uint(price)}).Error; err != nil {
				return err
			}
			break
		case 7:
			// 拍卖交易
			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}
			transferTx, err := h.client.Transfer(context.Background(), item.FileHash, common.HexToAddress(fromUser.Address), common.HexToAddress(toUser.Address), big.NewInt(int64(price)))
			if err != nil {
				return err
			}

			trade.TxHash = transferTx

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			if err := tx.Model(&item).Select("OwnerID", "Status", "Price").Updates(models.Item{OwnerID: toUser.ID, Status: 1, Price: item.Price}).Error; err != nil {
				return err
			}
			if err := tx.Model(models.Trade{}).Where("item_id = ?", item.ID).Updates(models.Trade{Status: 1}).Error; err != nil {
				return err
			}
			break
		case 8:
			// 报价
			if toUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			break
		case 9:
			// 取消交易
			if fromUser.ID != item.OwnerID {
				return errors.New("account and user error")
			}

			if err := tx.Create(&trade).Error; err != nil {
				return err
			}
			if err := tx.Model(&item).Select("Status", "Price").Updates(models.Item{Status: 1, Price: item.Price}).Error; err != nil {
				return err
			}
			if err := tx.Model(models.Trade{}).Where("item_id = ?", item.ID).Updates(models.Trade{Status: 1}).Error; err != nil {
				return err
			}
			break
		}

		return nil
	})

	return nil
}

func (h *Handler) SearchTradeList(c *gin.Context) {
	// 获取参数并检查
	current, err := strconv.Atoi(c.Query("current"))
	pageSize, err := strconv.Atoi(c.Query("pageSize"))
	tradeType, err := strconv.Atoi(c.Query("type"))
	userID, err := strconv.Atoi(c.Query("userID"))
	itemID, _ := strconv.Atoi(c.Query("itemID"))

	if err != nil {
		c.JSON(200, gin.H{
			"success":  false,
			"current":  0,
			"pageSize": 20,
			"message":  fmt.Sprintf("params err %s", err.Error()),
		})
		return
	}

	var trades []models.Trade
	err = h.db.
		Preload("From").Preload("Item").
		Limit(pageSize).Offset((current - 1) * pageSize).
		Where(&models.Trade{ItemID: uint(itemID), Type: uint(tradeType), ToUserID: uint(userID)}). // 当使用结构作为条件查询时，GORM 只会查询非零值字段。这意味着如果您的字段值为 0、''、false 或其他 零值，该字段不会被用于构建查询条件
		Find(&trades).
		Error

	if err != nil {
		c.JSON(200, gin.H{
			"success":  false,
			"current":  0,
			"pageSize": 20,
			"message":  fmt.Sprintf("db err %s", err.Error()),
		})
		return
	}

	c.JSON(200, gin.H{
		"success":  true,
		"data":     trades,
		"current":  current,
		"pageSize": pageSize,
	})
}

func (h *Handler) SearchAuthTradeList(c *gin.Context) {
	// 获取参数并检查
	current, err := strconv.Atoi(c.Query("current"))
	pageSize, err := strconv.Atoi(c.Query("pageSize"))
	itemID, err := strconv.Atoi(c.Query("itemID"))
	userID, err := strconv.Atoi(c.Query("userID"))
	if err != nil {
		c.JSON(200, gin.H{
			"success":  false,
			"current":  0,
			"pageSize": 20,
			"message":  fmt.Sprintf("params err %s", err.Error()),
		})
		return
	}

	var trades []models.Trade
	err = h.db.
		Limit(pageSize).Offset((current - 1) * pageSize).
		Preload("From").Preload("To").Preload("Item").
		Where(&models.Trade{ItemID: uint(itemID), ToUserID: uint(userID), Type: 5}). // 当使用结构作为条件查询时，GORM 只会查询非零值字段。这意味着如果您的字段值为 0、''、false 或其他 零值，该字段不会被用于构建查询条件
		Find(&trades).
		Error

	if err != nil {
		c.JSON(200, gin.H{
			"success":  false,
			"current":  0,
			"pageSize": 20,
			"message":  fmt.Sprintf("db err %s", err.Error()),
		})
		return
	}

	c.JSON(200, gin.H{
		"success":  true,
		"data":     trades,
		"current":  current,
		"pageSize": pageSize,
	})
}

func (h *Handler) SearchSaleTradeList(c *gin.Context) {
	// 获取参数并检查
	current, err := strconv.Atoi(c.Query("current"))
	pageSize, err := strconv.Atoi(c.Query("pageSize"))
	itemID, _ := strconv.Atoi(c.Query("itemID"))
	userID, err := strconv.Atoi(c.Query("userID"))
	if err != nil {
		c.JSON(200, gin.H{
			"success":  false,
			"current":  0,
			"pageSize": 20,
			"message":  fmt.Sprintf("params err %s", err.Error()),
		})
		return
	}

	var trades []models.Trade
	err = h.db.
		Limit(pageSize).Offset((current-1)*pageSize).
		Preload("From").Preload("To").Preload("Item").
		Where(&models.Trade{ItemID: uint(itemID), ToUserID: uint(userID)}). // 当使用结构作为条件查询时，GORM 只会查询非零值字段。这意味着如果您的字段值为 0、''、false 或其他 零值，该字段不会被用于构建查询条件
		Where("type = ?", 3).Or("type = ?", 7).
		Find(&trades).
		Error

	if err != nil {
		c.JSON(200, gin.H{
			"success":  false,
			"current":  0,
			"pageSize": 20,
			"message":  fmt.Sprintf("db err %s", err.Error()),
		})
		return
	}

	c.JSON(200, gin.H{
		"success":  true,
		"data":     trades,
		"current":  current,
		"pageSize": pageSize,
	})
}
